/**
 *
 */
package com.angel.common.providers.base;

import java.io.Serializable;

import com.angel.common.providers.exceptions.CannotGetExcludeValueForObjectException;
import com.angel.common.providers.managers.FieldExcludeValueAnnotationManager;
import com.angel.common.providers.managers.MethodExcludeValueAnnotationManager;
import com.angel.dao.generic.interfaces.GenericDAO;

/**
 * @author William
 *
 */
public class ExcludeRangeValueProvider<T extends Object, H extends Comparable<Object>> extends ObjectProvider<T>{

	private FieldExcludeValueAnnotationManager fieldExcludeManager = new FieldExcludeValueAnnotationManager();
	private MethodExcludeValueAnnotationManager methodExcludeManager = new MethodExcludeValueAnnotationManager();
	private static final long serialVersionUID = -2380432275125208115L;
	private Comparable<H> maximun;
	private Comparable<H> minimun;

	public ExcludeRangeValueProvider(GenericDAO<T, Serializable> genericDAO, Class<T> classObject, Comparable<H> maximun, Comparable<H> minimun){
		super(genericDAO, classObject);
		this.maximun = maximun;
		this.minimun = minimun;
	}

	public ExcludeRangeValueProvider(Class<T> classObject, Comparable<H> maximun, Comparable<H> minimun){
		super(classObject);
		this.maximun = maximun;
		this.minimun = minimun;
	}

	/**
	 * @return the maximun
	 */
	protected Comparable<H> getMaximun() {
		return maximun;
	}

	/**
	 * @param maximun the maximun to set
	 */
	protected void setMaximun(Comparable<H> maximun) {
		this.maximun = maximun;
	}

	/**
	 * @return the minimun
	 */
	protected Comparable<H> getMinimun() {
		return minimun;
	}

	/**
	 * @param minimun the minimun to set
	 */
	protected void setMinimun(Comparable<H> minimun) {
		this.minimun = minimun;
	}

	@Override
	public boolean addObject(String name, T object){
		boolean addedObject = false;
		boolean canFindExcludeValueByField = fieldExcludeManager.canFindExcludeValueFor(this.getClass());
		if(canFindExcludeValueByField){
			addedObject = this.addObjectProcessingByFieldExcludeValue(name, object);
		} else {
			boolean canFindExcludeValueByMethod = methodExcludeManager.canProcessAnnotationAt(object);
			if(canFindExcludeValueByMethod){
				addedObject = this.addObjectProcessingByMethodExcludeValue(name, object);
			} else {
				throw new CannotGetExcludeValueForObjectException("It could NOT get exclude objet for object to adds with field or method exclude value annotation.");
			}
		}
		return addedObject;
	}

	@Override
	public boolean addObject(T object){
		boolean addedObject = false;
		boolean canFindExcludeValueByField = fieldExcludeManager.canFindExcludeValueFor(this.getClass());
		if(canFindExcludeValueByField){
			addedObject = this.addObjectProcessingByFieldExcludeValue(object);
		} else {
			boolean canFindExcludeValueByMethod = methodExcludeManager.canProcessAnnotationAt(object);
			if(canFindExcludeValueByMethod){
				addedObject = this.addObjectProcessingByMethodExcludeValue(object);
			} else {
				throw new CannotGetExcludeValueForObjectException("It could NOT get exclude objet for object to adds with field or method exclude value annotation.");
			}
		}
		return addedObject;
	}

	@SuppressWarnings("unchecked")
	private boolean addObjectProcessingByMethodExcludeValue(String name, T object){
		boolean addedObject = false;
		H value = (H)  methodExcludeManager.getExcludeValueFor(this);
		boolean isBetweenLimit = this.compareValueWithExcludeLimits(value);
		if(isBetweenLimit){
			addedObject = super.addObject(name, object);
		}
		return addedObject;
	}

	@SuppressWarnings("unchecked")
	private boolean addObjectProcessingByMethodExcludeValue(T object){
		boolean addedObject = false;
		H value = (H)  methodExcludeManager.getExcludeValueFor(this);
		boolean isBetweenLimit = this.compareValueWithExcludeLimits(value);
		if(isBetweenLimit){
			addedObject = super.addObject(object);
		}
		return addedObject;
	}

	@SuppressWarnings("unchecked")
	private boolean addObjectProcessingByFieldExcludeValue(String name, T object){
		boolean addedObject = false;
		H value = (H) methodExcludeManager.getExcludeValueFor(this);
		boolean isBetweenLimit = this.compareValueWithExcludeLimits(value);
		if(isBetweenLimit){
			addedObject = super.addObject(name, object);
		}
		return addedObject;
	}

	@SuppressWarnings("unchecked")
	private boolean addObjectProcessingByFieldExcludeValue(T object){
		boolean addedObject = false;
		H value = (H) methodExcludeManager.getExcludeValueFor(this);
		boolean isBetweenLimit = this.compareValueWithExcludeLimits(value);
		if(isBetweenLimit){
			addedObject = super.addObject(object);
		}
		return addedObject;
	}

	private boolean compareValueWithExcludeLimits(H value) {
		boolean isBetweenInLimit = false;
		if(value != null){
			if(minimun.compareTo(value) < 0 && maximun.compareTo(value) > 0){
				isBetweenInLimit = true;
			}
		} else {
			throw new CannotGetExcludeValueForObjectException("It cannot add a null object to exclude object provider.");
		}
		return isBetweenInLimit;
	}
}
